package jkcp;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;

import java.nio.ByteOrder;

public class IkcpTest implements IOutput {
	
	// 模拟网络
	public static LatencySimulator vnet;

	
	// 模拟网络：模拟发送一个 udp包
	public int Output(ByteBuf buf, int _len, Ikcpcb kcp, Object user) {
		long id = (Long)user;
        //println("send!!!!", id, _len)
		if (vnet.send((int)id, buf, _len) != 1) {
	                //println("wocao !!!", id, _len)
	        }
		return 0;
	}
	
	// 测试用例
	public static void test(int mode)
	{

		// 创建模拟网络：丢包率10%，Rtt 60ms~125ms
		vnet = new LatencySimulator();
        vnet.Init(10, 60, 125, 1000);

		// 创建两个端点的 kcp对象，第一个参数 conv是会话编号，同一个会话需要相同
		// 最后一个是 user参数，用来传递标识
        long a = 0;
        long b = 1;
        Ikcpcb kcp1 = IKCPSEG.Ikcp_create(0x11223344, a);
        Ikcpcb kcp2 = IKCPSEG.Ikcp_create(0x11223344, b);
		// 设置kcp的下层输出，这里为 udp_output，模拟udp网络输出函数
        IkcpTest udp_output = new IkcpTest();
		kcp1.iOutPut = udp_output;
		kcp2.iOutPut = udp_output;
		long current = IkcpTest_h.iclock();
		long slap = current+20;
		int index = 0;
		int next = 0;
		long sumrtt = 0;
		int count =0;
		int maxrtt = 0;
		// 配置窗口大小：平均延迟200ms，每20ms发送一个包，
		// 而考虑到丢包重发，设置最大收发窗口为128
		IKCPSEG.Ikcp_wndsize(kcp1, 128, 128);
		IKCPSEG.Ikcp_wndsize(kcp2, 128, 128);

		// 判断测试用例的模式
		if (mode == 0) {
			// 默认模式
			IKCPSEG.Ikcp_nodelay(kcp1, 0, 10, 0, 0);
			IKCPSEG.Ikcp_nodelay(kcp2, 0, 10, 0, 0);
		} else if (mode == 1) {
			// 普通模式，关闭流控等
			IKCPSEG.Ikcp_nodelay(kcp1, 0, 10, 0, 1);
			IKCPSEG.Ikcp_nodelay(kcp2, 0, 10, 0, 1);
		}	else {
			// 启动快速模式
			// 第二个参数 nodelay-启用以后若干常规加速将启动
			// 第三个参数 interval为内部处理时钟，默认设置为 10ms
			// 第四个参数 resend为快速重传指标，设置为2
			// 第五个参数 为是否禁用常规流控，这里禁止
			IKCPSEG.Ikcp_nodelay(kcp1, 1, 10, 2, 1);
			IKCPSEG.Ikcp_nodelay(kcp2, 1, 10, 2, 1);
		}

		ByteBuf buffer = PooledByteBufAllocator.DEFAULT.directBuffer(2000);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		int hr;
		long ts1 = IkcpTest_h.iclock();

		for (;;){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			current = IkcpTest_h.iclock();
			IKCPSEG.Ikcp_update(kcp1,IkcpTest_h.iclock());
			IKCPSEG.Ikcp_update(kcp2, IkcpTest_h.iclock());

			// 每隔 20ms，kcp1发送数据
			for (; current >= slap; slap += 20) {
				ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer(2000);
				buf.order(ByteOrder.LITTLE_ENDIAN);
				buf.writeInt(index);
				index++;
				buf.writeLong(current);
				// 发送上层协议包
				byte[] bytes = new byte[buf.readableBytes()];
				buf.readBytes(bytes);
				IKCPSEG.Ikcp_send(kcp1, bytes, 8);
                //println("now", iclock())
			}

			// 处理虚拟网络：检测是否有udp包从p1->p2
	                for(;;) {
				hr = vnet.recv(1, buffer, 2000);
				if (hr < 0) { 
	                                break ;
	                        }
				// 如果 p2收到udp，则作为下层协议输入到kcp2
				IKCPSEG.Ikcp_input(kcp2, buffer, hr);
			}

			// 处理虚拟网络：检测是否有udp包从p2->p1
	                for(;;) {
				hr = vnet.recv(0, buffer, 2000);
				if (hr < 0) { break; }
				// 如果 p1收到udp，则作为下层协议输入到kcp1
				IKCPSEG.Ikcp_input(kcp1, buffer, hr);
	                        //println("@@@@", hr, r)
			}

			// kcp2接收到任何包都返回回去
	                for(;;) {
				hr = IKCPSEG.Ikcp_recv(kcp2, buffer, 10);
				// 没有收到包就退出
				if (hr < 0) { break; }
				// 如果收到包就回射
				ByteBuf buf = buffer;
//				buffer.order(ByteOrder.LITTLE_ENDIAN);
				long sn = buf.readUnsignedInt();
				
				byte[] bytes = new byte[buf.readableBytes()];
				buf.readBytes(bytes);
				IKCPSEG.Ikcp_send(kcp2, bytes, hr);
			}

			// kcp1收到kcp2的回射数据
	                for (;;){
				hr = IKCPSEG.Ikcp_recv(kcp1, buffer, 10);
				ByteBuf buf = buffer;
				// 没有收到包就退出
				if (hr < 0) { break; }
				long sn = buf.readUnsignedInt();
				long ts = buf.readUnsignedInt();
				long rtt = current - ts;
				
				
				if (sn != next) {
					// 如果收到的包不连续
	                                //for i:=0;i<8 ;i++ {
	                                        //println("---", i, buffer[i])
	                                //}
					System.err.println("ERROR sn "+ count+ "<->"+ next+"  "+ sn);
                    return;
				}

				next++;;
				sumrtt += rtt;
				count++;
				if (rtt > maxrtt) { maxrtt = (int)rtt; }
				
				System.err.println("[RECV] mode="+ mode+ " sn="+sn+ " rtt="+ rtt);
			}
			if (next > 100) { break; }
		}

		ts1 = IkcpTest_h.iclock() - ts1;
		
		String[] names = new String[]{ "default", "normal", "fast" };
		System.err.println("%s mode result (%dms):\n"+ names[mode]+"  "+ ts1);
		
		System.err.println("avgrtt=%d maxrtt=%d\n"+ sumrtt / count+"  "+ maxrtt);
	}
	public static void main(String[] args) {
		test(0);
		
	}
	

//	func TestNetwork(t *testing.T) {
//		test(0);	// 默认模式，类似 TCP：正常模式，无快速重传，常规流控
//		test(1);	// 普通模式，关闭流控等
//		test(2);	// 快速模式，所有开关都打开，且关闭流控
//	}

}
